package cn.remex.core.util;

import cn.remex.core.CoreSvo;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.exception.StringHandleException;
import cn.remex.core.reflect.ReflectUtil;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.Map;
import java.util.function.BiConsumer;

/**
 * json处理工具类
 */
public class JsonHelper {
//初步证实当写入对象为流是，此对象线程不安全 LHY 2014-11-2
//	private static ObjectMapper mapper = new ObjectMapper();
//	static {
//		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
//		mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
//		mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
//		mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES,true);
//	}

	private final static String LocalObjectMapper = "JsonHelper";

	/**
	 * 对象转化为Json字符串
	 *
	 * @param obj java对象
	 * @return String 字符串
	 */
	public static String toJsonString(Object obj) {
		try {
			return obtainLocalObjectMapper().writeValueAsString(obj);
		} catch (JsonProcessingException e) {
			throw new StringHandleException(ServiceCode.FAIL, "无法将对象转化为Json字符串", e);
		}
	}

	private static ObjectMapper obtainLocalObjectMapper() {
		ObjectMapper mapper = (ObjectMapper) CoreSvo.valLocal(LocalObjectMapper);
		if (null == mapper) {
			mapper = new ObjectMapper();
			//允许不用双引号将fieldName括起来。
			mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
			mapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
			//不允许自动关闭输出流。
			mapper.configure(com.fasterxml.jackson.core.JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);

			//序列化时：忽略nullbean导致的失败
			mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
			//序列化时：输入map中的null值
			mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
			//序列化时：忽略空字段
			mapper.setSerializationInclusion(Include.NON_NULL);

			//反序列化时：忽略没有匹配上的属性
			mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
			//反序列化时：将空字符串标示为空对象。
			mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);

			CoreSvo.putLocal(LocalObjectMapper, mapper);
		}
		return mapper;
	}

	/**
	 * 向流中写入Json字符串
	 *
	 * @param writer 字符流
	 * @param value  java对象
	 */
	public static void writJsonString(Writer writer, Object value) {
		try {
			obtainLocalObjectMapper().writeValue(writer, value);
		} catch (IOException e) {
			handleJsonException(e, null, value);
		}
	}

	/*
	 * 将Json字符串转化为Java对象
	 */
	public static <T> T toJavaObject(String jsonString, Class<T> clazz) {
		try {
			return Judgment.nullOrBlank(jsonString) ? null : obtainLocalObjectMapper().readValue(jsonString, clazz);
		} catch (IOException e) {
			handleJsonException(e, clazz, null);return null;//never arrive here
		}
	}

	public static JsonNode toJsonNode(String jsonString) {
		ObjectMapper mapper = obtainLocalObjectMapper();
		try {
			return mapper.readTree(jsonString);
		} catch (IOException e) {
			handleJsonException(e, JsonNode.class, null);return null;//never arrive here
		}
	}

	public static String readString(JsonNode jsonNode, String fieldName) {
		JsonNode subNode = jsonNode.get(fieldName);
		return null == subNode ? null : subNode.textValue();
	}

	public static String readStringByPath(JsonNode jsonNode, String path) {
		JsonNode subNode = jsonNode.findPath(path);
		return null == subNode ? null : subNode.textValue();
	}
	public static void eachNode(String jsonString, BiConsumer<String, JsonNode> nodeConsumer) {
		try {
			ObjectMapper mapper = obtainLocalObjectMapper();
			Iterator<Map.Entry<String, JsonNode>> nodes = mapper.readTree(jsonString).fields();
			while (nodes.hasNext()) {
				Map.Entry<String, JsonNode> node = nodes.next();
				nodeConsumer.accept(node.getKey(), node.getValue());
			}
		} catch (IOException e) {
			handleJsonException(e, JsonNode.class, null);
		}
	}

	public static <T> T toJavaObject(String jsonString, Type clazz) {
		try {
			ObjectMapper mapper = obtainLocalObjectMapper();
			JavaType javaType = mapper.getTypeFactory().constructParametricType(ReflectUtil.obtainClass(clazz), ReflectUtil.obtainParameterClasses(clazz));
			return Judgment.nullOrBlank(jsonString) ? null : obtainLocalObjectMapper().readValue(jsonString, javaType);
		} catch (IOException e) {
			handleJsonException(e, clazz, null);return null;//never arrive here
		}
	}

	/*
	 * 将Json字符串转化为Java对象
	 */
	public static <T> T toJavaObject(String jsonString, Class<T> clazz, String path) {
		try {
			return obtainLocalObjectMapper().readValue(obtainLocalObjectMapper().readTree(jsonString).path(path).traverse(), clazz);
		} catch (IOException e) {
			handleJsonException(e, clazz, null);return null;//never arrive here
		}
	}

	/*
	 * 将Json字符串转化为Java对象
	 */
	public static <T> T toJavaObject(Reader reader, Class<T> clazz) {
		try {
			return obtainLocalObjectMapper().readValue(reader, clazz);
		} catch (IOException e) {
			handleJsonException(e, clazz, null);return null;//never arrive here
		}
	}
	private static <T> T handleJsonException(Exception e, Type clazz, Object value) {
		if (e instanceof JsonParseException) {
			throw new StringHandleException(ServiceCode.FAIL, "Json 数据格式错误, "+ (clazz!=null?"class=" + clazz.toString():value!=null?"class=" +value.getClass():"")
					+ ", JacksonMessage=" + ((JsonParseException)e).getRequestPayload(), e);
		}else if (e instanceof JsonMappingException) {
			throw new StringHandleException(ServiceCode.FAIL, "Json 数据格式错误, "+ (clazz!=null?"class=" + clazz.toString():value!=null?"class=" +value.getClass():"")
					+ ", path=" + ((JsonMappingException)e).getPath(), e);
		}else if (e instanceof JsonProcessingException) {
			throw new StringHandleException(ServiceCode.FAIL, "Json 数据格式错误, " + (clazz != null ? "class=" + clazz.toString() : value != null ? "class=" + value.getClass() : "")
					+ ", JacksonMessage=" + ((JsonProcessingException) e).getOriginalMessage().substring(0, 100), e);
		}else {
			throw new StringHandleException(ServiceCode.FAIL, "Json 数据格式错误, "+ (clazz!=null?"class=" + clazz.toString():value!=null?"class=" +value.getClass():""), e);
		}


	}
}
